package org.chronologger.poppaea.client.domain;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.NotPersistent;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import org.chronologger.poppaea.client.utils.HasColor;
import org.chronologger.poppaea.client.utils.Logger;
import org.chronologger.poppaea.client.widgets.LocationWidget;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Location implements Iterable<Scene>, Serializable, HasColor {

	private static final long serialVersionUID = 1L;

	@PrimaryKey
	@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
	private Long id = null;

	@Persistent
	private String name;

	@NotPersistent
	private List<Scene> scenes = new ArrayList<Scene>();

	@Persistent
	private Long chronologyId;

	@Persistent
	private String color = "white";
	
	private transient Scene lastPushedScene = null;
	private transient boolean updateLater = false;
	private transient LocationWidget widget;
	
	Location() {
	}

	public Location(ChronologyData cdata) throws NotSupportedOnClientException {
		if (GWT.isClient()) {
			throw new NotSupportedOnClientException();
		} else {
			chronologyId = cdata.getId();
		}
	}

	public Location(Long chronoId) {
		chronologyId = chronoId;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setScenes(List<Scene> scenes) {
		this.scenes = scenes;
	}

	public List<Scene> getScenes() {
		return scenes;
	}

	protected void setChronologyId(Long cdataId) {
		this.chronologyId = cdataId;
	}

	protected Long getChronologyId() {
		return chronologyId;
	}

	public Iterator<Scene> iterator() {
		return scenes.iterator();
	}

	private void pushScene(final Scene scene) {
		ChronologyData.getService().addScene(getId(),
				new AsyncCallback<Scene>() {

					public void onSuccess(Scene result) {
						scene.setId(result.getId());
					}

					public void onFailure(Throwable caught) {
						Logger.error("Couldn't create scene");
					}
				});
		lastPushedScene = scene;
	}
	
	protected void setId(Long id) {
		this.id = id;
		// push scenes that haven't been pushed yet
		if(updateLater) 
			updateOnServer();
		if(lastPushedScene != null) {
			for(int i = scenes.indexOf(lastPushedScene)+1; i < scenes.size(); i++) {
				pushScene(scenes.get(i));
			}	
		}
	}

	public Long getId() {
		return id;
	}

	public Scene addScene() {
		final Scene newScene = new Scene();
		if(id != null) {
			pushScene(newScene);
		}
		scenes.add(newScene);
		return newScene;
	}
	
	public void updateOnServer() {
		if (id == null) {
			updateLater = true;
			Logger.notice("Not persisted yet, updating later");
		} else {
			// don't send scenes to server
			List<Scene> scenes = this.scenes;
			this.scenes = null;
			
			ChronologyData.getService().updateLocation(this,
					new AsyncCallback<Void>() {

						public void onFailure(Throwable caught) {
							Logger.error("Couldn't update location");
						}

						public void onSuccess(Void result) {
							Logger.notice("Location updated.");
						}
					});
			
			this.scenes = scenes;
		}
	}

	public void setColor(String color) {
		this.color = color;
	}

	public String getColor() {
		return color;
	}

	public void setWidget(LocationWidget widget) {
		this.widget = widget;
	}

	public LocationWidget getWidget() {
		return widget;
	}

}